package com.cloudree.gllib.shape;

import android.opengl.GLES20;
import android.opengl.Matrix;

import com.cloudree.gllib.BaseApp;
import com.cloudree.gllib.R;
import com.cloudree.gllib.constants.RenderData;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

/**
 * Created by Administrator on 2017/8/9.
 */
public class IBOMap extends Shape {

    private FloatBuffer vertexBuffer;
    private ShortBuffer indexBuffer;
    private int[] vbo;
    private int[] ibo;
    private float[] vertexData;
    private short[] indexData;

    @Override
    public void loadingMaterial() {
        vertexData = RenderData.IBO.vertexData(32, 32, 3 + 4 + 3);
        indexData = RenderData.IBO.indexData(32, 32);

        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);
        vertexBuffer.position(0);
        indexBuffer = ByteBuffer.allocateDirect(indexData.length * 4).order(ByteOrder.nativeOrder()).asShortBuffer().put(indexData);
        indexBuffer.position(0);

    }

    @Override
    public void compileShader() {
        int vertexShader = generateShader(GLES20.GL_VERTEX_SHADER, getVertexShaderCode());
        int fragmentShader = generateShader(GLES20.GL_FRAGMENT_SHADER, getFragmentShaderCode());
        String[] attrs = new String[]{"aPosition", "aColor", "aNormal"};
        mProgram = generateGlProgram(vertexShader, fragmentShader, attrs);

        vbo = new int[1];
        ibo = new int[1];

//        bind buffer
        GLES20.glGenBuffers(1, vbo, 0);
        GLES20.glGenBuffers(1, ibo, 0);

        if (vbo[0] > 0 && ibo[0] > 0) {
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
            GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);

            GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
            GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * 2, indexBuffer, GLES20.GL_STATIC_DRAW);

            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
            GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
        } else {
            throw new RuntimeException("Error generate vbo or ibo");
        }

    }

    @Override
    public void draw(float[] mvpMatrix, float[] modelMatrix, float[] viewMatrix, float[] projectionMatrix) {

    }
    public void draw(float[] mvpMatrix, float[] modelMatrix, float[] viewMatrix, float[] projectionMatrix,float[] lightEyeSpace) {
        GLES20.glUseProgram(mProgram);
        int mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        int mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVMatrix");
        int mLightPositionHandle = GLES20.glGetUniformLocation(mProgram, "uLightPosition");

        int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        int mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
        int mNormalHandle = GLES20.glGetAttribLocation(mProgram, "aNormal");

        if (vbo[0] > 0 && ibo[0] > 0) {
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
            //bind attribute
            GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 40, 0);
            GLES20.glEnableVertexAttribArray(mPositionHandle);
            GLES20.glVertexAttribPointer(mNormalHandle, 3, GLES20.GL_FLOAT, false, 40, 3*4);
            GLES20.glEnableVertexAttribArray(mNormalHandle);
            GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 40, (3+3)*4);
            GLES20.glEnableVertexAttribArray(mColorHandle);

            //combine matrix
            // (which currently contains model * view).
            Matrix.multiplyMM(mvpMatrix, 0, viewMatrix, 0, modelMatrix, 0);

            // Pass in the modelview matrix.
            GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mvpMatrix, 0);

            // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
            // (which now contains model * view * projection).
            Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvpMatrix, 0);
//            System.arraycopy(mTemporaryMatrix, 0, mvpMatrix, 0, 16);

            // Pass in the combined matrix.
            GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

            // Pass in the light position in eye space.
            GLES20.glUniform3f(mLightPositionHandle, lightEyeSpace[0], lightEyeSpace[1], lightEyeSpace[2]);



            GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
            GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexData.length, GLES20.GL_UNSIGNED_SHORT, 0);

            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
            GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
        }

    }
    @Override
    public String getVertexShaderCode() {
        return readRawFile(BaseApp.getApp(), R.raw.ibo_map_vertex_shader);
    }

    @Override
    public String getFragmentShaderCode() {
        return readRawFile(BaseApp.getApp(), R.raw.ibo_map_fragment_shader);
    }
}
